/*
 * Copyright 2010 Electronic Business Systems Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package gr.ebs.gssdroid.resource;

import java.net.URLDecoder;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;



/**
 * @author kman
 */
public class FileResource extends RestResource {

	public FileResource(String aUri) {
		super(aUri);
	}

	String name;

	String owner;

	String createdBy;

	String modifiedBy;

	Date creationDate;

	Date modificationDate;

	String contentType;

	Long contentLength;

	boolean readForAll;

	Boolean versioned;
	
	Boolean shared;
	
	Integer version;

	String etag;

	boolean deleted = false;

	List<String> tags = new ArrayList<String>();

	Set<PermissionHolder> permissions = new HashSet<PermissionHolder>();

	String folderURI;

	String path;

	String folderName;

	/**
	 * Retrieve the folderName.
	 *
	 * @return the folderName
	 */
	public String getFolderName() {
		return folderName;
	}

	/**
	 * Modify the folderName.
	 *
	 * @param aFolderName the folderName to set
	 */
	public void setFolderName(String aFolderName) {
		folderName = aFolderName;
	}

	/**
	 * Retrieve the path.
	 *
	 * @return the path
	 */
	public String getPath() {
		return path;
	}

	/**
	 * Modify the path.
	 *
	 * @param aPath the path to set
	 */
	public void setPath(String aPath) {
		path = aPath;
	}

	/**
	 * Retrieve the name.
	 *
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	/**
	 * Modify the name.
	 *
	 * @param aName the name to set
	 */
	public void setName(String aName) {
		name = aName;
	}

	/**
	 * Retrieve the owner.
	 *
	 * @return the owner
	 */
	public String getOwner() {
		return owner;
	}

	/**
	 * Modify the owner.
	 *
	 * @param newOwner the owner to set
	 */
	public void setOwner(String newOwner) {
		owner = newOwner;
	}

	/**
	 * Retrieve the createdBy.
	 *
	 * @return the createdBy
	 */
	public String getCreatedBy() {
		return createdBy;
	}

	/**
	 * Modify the createdBy.
	 *
	 * @param aCreatedBy the createdBy to set
	 */
	public void setCreatedBy(String aCreatedBy) {
		createdBy = aCreatedBy;
	}

	/**
	 * Retrieve the modifiedBy.
	 *
	 * @return the modifiedBy
	 */
	public String getModifiedBy() {
		return modifiedBy;
	}

	/**
	 * Modify the modifiedBy.
	 *
	 * @param aModifiedBy the modifiedBy to set
	 */
	public void setModifiedBy(String aModifiedBy) {
		modifiedBy = aModifiedBy;
	}

	/**
	 * Retrieve the creationDate.
	 *
	 * @return the creationDate
	 */
	public Date getCreationDate() {
		return creationDate;
	}

	/**
	 * Modify the creationDate.
	 *
	 * @param aCreationDate the creationDate to set
	 */
	public void setCreationDate(Date aCreationDate) {
		creationDate = aCreationDate;
	}

	/**
	 * Retrieve the modificationDate.
	 *
	 * @return the modificationDate
	 */
	public Date getModificationDate() {
		return modificationDate;
	}

	/**
	 * Modify the modificationDate.
	 *
	 * @param aModificationDate the modificationDate to set
	 */
	public void setModificationDate(Date aModificationDate) {
		modificationDate = aModificationDate;
	}

	/**
	 * Retrieve the contentType.
	 *
	 * @return the contentType
	 */
	public String getContentType() {
		return contentType;
	}

	/**
	 * Modify the contentType.
	 *
	 * @param newContentType the contentType to set
	 */
	public void setContentType(String newContentType) {
		contentType = newContentType;
	}

	/**
	 * Retrieve the contentLength.
	 *
	 * @return the contentLength
	 */
	public Long getContentLength() {
		return contentLength;
	}

	/**
	 * Modify the contentLength.
	 *
	 * @param newContentLength the contentLength to set
	 */
	public void setContentLength(Long newContentLength) {
		contentLength = newContentLength;
	}

	/**
	 * Retrieve the readForAll.
	 *
	 * @return the readForAll
	 */
	public boolean isReadForAll() {
		return readForAll;
	}

	/**
	 * Modify the readForAll.
	 *
	 * @param newReadForAll the readForAll to set
	 */
	public void setReadForAll(boolean newReadForAll) {
		readForAll = newReadForAll;
	}

	/**
	 * Retrieve the versioned.
	 *
	 * @return the versioned
	 */
	public boolean isVersioned() {
		return versioned;
	}

	/**
	 * Modify the versioned.
	 *
	 * @param newVersioned the versioned to set
	 */
	public void setVersioned(boolean newVersioned) {
		versioned = newVersioned;
	}

	/**
	 * Retrieve the version.
	 *
	 * @return the version
	 */
	public Integer getVersion() {
		return version;
	}

	/**
	 * Modify the version.
	 *
	 * @param aVersion the version to set
	 */
	public void setVersion(Integer aVersion) {
		version = aVersion;
	}

	/**
	 * Retrieve the etag.
	 *
	 * @return the etag
	 */
	public String getEtag() {
		return etag;
	}

	/**
	 * Modify the etag.
	 *
	 * @param anEtag the etag to set
	 */
	public void setEtag(String anEtag) {
		etag = anEtag;
	}

	/**
	 * Retrieve the tags.
	 *
	 * @return the tags
	 */
	public List<String> getTags() {
		return tags;
	}

	/**
	 * Modify the tags.
	 *
	 * @param newTags the tags to set
	 */
	public void setTags(List<String> newTags) {
		tags = newTags;
	}

	/**
	 * Retrieve the permissions.
	 *
	 * @return the permissions
	 */
	public Set<PermissionHolder> getPermissions() {
		return permissions;
	}

	/**
	 * Modify the permissions.
	 *
	 * @param newPermissions the permissions to set
	 */
	public void setPermissions(Set<PermissionHolder> newPermissions) {
		permissions = newPermissions;
	}

	/**
	 * Retrieve the deleted.
	 *
	 * @return the deleted
	 */
	public boolean isDeleted() {
		return deleted;
	}

	/**
	 * Modify the deleted.
	 *
	 * @param newDeleted the deleted to set
	 */
	public void setDeleted(boolean newDeleted) {
		deleted = newDeleted;
	}

	/**
	 * Retrieve the folderURI.
	 *
	 * @return the folderURI
	 */
	public String getFolderURI() {
		return folderURI;
	}

	/**
	 * Modify the folderURI.
	 *
	 * @param aFolderURI the folderURI to set
	 */
	public void setFolderURI(String aFolderURI) {
		folderURI = aFolderURI;
	}

	@Override
	public void createFromJSON(String text) throws JSONException {
		JSONObject metadata = new JSONObject(text);
		name = unmarshallString(metadata, "name");
		name = URLDecoder.decode(name);
		path = unmarshallString(metadata, "path");
		path = URLDecoder.decode(path);
		owner = unmarshallString(metadata, "owner");
		createdBy = unmarshallString(metadata, "createdBy");
		modifiedBy = unmarshallString(metadata, "modifiedBy");
		contentType = unmarshallString(metadata, "content");
		readForAll = unmarshallBoolean(metadata, "readForAll");
		versioned = unmarshallBoolean(metadata, "versioned");
		shared = unmarshallBoolean(metadata, "shared");
		String versionString = unmarshallString(metadata, "version");
		if (versionString != null)
			version = new Integer(versionString);

		deleted = unmarshallBoolean(metadata, "deleted");
		
		JSONObject folder = getJSONObject(metadata,"folder");
		if (folder != null) {
			folderURI = unmarshallString(folder, "uri");
			folderName = unmarshallString(folder, "name");
			if(folderName != null)
				folderName = URLDecoder.decode(folderName);
		}
		JSONArray perm = getJSONArray(metadata, "permissions");
		if (perm != null) {
				for (int i = 0; i < perm.length(); i++) {
					JSONObject obj = perm.getJSONObject(i);
					if (obj != null) {
						PermissionHolder permission = new PermissionHolder();
						String user = unmarshallString(obj, "user");
						if (user != null)
							permission.setUser(unmarshallString(obj, "user"));
						String group = unmarshallString(obj, "groupUri");
						if (group != null) {
							group = URLDecoder.decode(group);
							permission.setGroup(group);
						}
						else{
							group = unmarshallString(obj, "group");
							if(group!=null){
								group = URLDecoder.decode(group);
								permission.setGroup(group);
							}
						}
						permission.setRead(unmarshallBoolean(obj, "read"));
						permission.setWrite(unmarshallBoolean(obj, "write"));
						permission.setModifyACL(unmarshallBoolean(obj, "modifyACL"));
						permissions.add(permission);
					}
				}

		}
		perm = getJSONArray(metadata,"tags");
		if (perm != null)
			for (int i = 0; i < perm.length(); i++) {
				String obj = perm.getString(i);
				if(obj != null)
					tags.add(URLDecoder.decode(obj));
			}
		String testString = unmarshallString(metadata, "creationDate");
		if (testString != null)
			creationDate = new Date(new Long(testString));
		testString = unmarshallString(metadata, "modificationDate");
		if (testString != null)
			modificationDate = new Date(new Long(testString));
		testString = unmarshallString(metadata, "size");
		if (testString != null)
			contentLength = Long.parseLong(testString);		
	}

	/**
	 * Return the file size in a humanly readable form, using SI units to denote
	 * size information, e.g. 1 KB = 1000 B (bytes).
	 *
	 * @return the fileSize
	 */
	public String getFileSizeAsString() {
		return getFileSizeAsString(contentLength);
	}

	/**
	 * Return the given size in a humanly readable form, using SI units to denote
	 * size information, e.g. 1 KB = 1000 B (bytes).
	 *
	 * @param size in bytes
	 * @return the size in human readable string
	 */
	public static String getFileSizeAsString(long size) {
		if (size < 1024)
			return String.valueOf(size) + " B";
		else if (size <= 1024 * 1024)
			return getSize(size, 1024D) + " KB";
		else if (size <= 1024 * 1024 * 1024)
			return getSize(size, (1024D * 1024D)) + " MB";
		return getSize(size, (1024D * 1024D * 1024D)) + " GB";
	}

	private static String getSize(Long size, Double division) {
		Double res = Double.valueOf(size.toString()) / division;
		NumberFormat nf =new DecimalFormat("######.#");
		return nf.format(res);
		
	}

	public boolean isShared(){
		if (isReadForAll())
			return true;
		if(permissions != null)
			for(PermissionHolder perm : permissions){
				if(perm.getUser() != null && !owner.equals(perm.getUser()))
					return true;
				if(perm.getGroup() != null)
					return true;
			}
		return false;
	}

	public boolean isShared(String ownerUser){
		if (isReadForAll())
			return true;
		if(permissions != null)
			for(PermissionHolder perm : permissions){
				if(perm.getUser() != null && !ownerUser.equals(perm.getUser()))
					return true;
				if(perm.getGroup() != null)
					return true;
			}
		return false;
	}
	
	public Boolean getShared() {
		return shared;
	}
	
	public void setShared(Boolean shared) {
		this.shared = shared;
	}

	@Override
	public String getLastModifiedSince() {
		if(modificationDate != null)
			return getDate(modificationDate.getTime());
		return null;
	}
	
	public String getTagsAsString(){
		if(tags==null||tags.size()==0)
			return "";
		StringBuffer tagsBuffer = new StringBuffer();
		Iterator<String> i = getTags().iterator();
		while (i.hasNext()) {
			String tag =  i.next();
			tagsBuffer.append(tag).append(", ");
		}
		if (tagsBuffer.length() > 1)
			tagsBuffer.delete(tagsBuffer.length() - 2, tagsBuffer.length() - 1);
		return tagsBuffer.toString();
	}
}
